package junk;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import com.sun.tools.javac.util.List;

import processing.core.PApplet;


public class Annotations extends MoveObject {
	public static PApplet parent;
	public static boolean sizeByValue;
	public static float[] centerRadius;	
		
	public boolean isActiveItem;
	public boolean isInRing;
	public boolean isInCenter;
	public boolean fromContinuous = false;
	public int level;
	public int myLevels;
	public int numChildren;
	public float x1,y1;
	public float centerX, centerY;
	public float labelX, labelY;
	public float midX, midY;
	public float groupTotalExpression;
	public float percentParentExpression;
	public float[][] bounds;
	public String annotationType;
	public String parentType;
	public String groupName;
	public String[] annotationOrder;	
	public String[][] annotationSubGroups;
	public ArrayList subGroups;	
	public Gene[] genes;	
	public Annotations parentAnnotations;	
	public Annotations annotationCopy;
	public Annotations[] children;	
	
	public Annotations(String type, String gType, String pType, Gene [] g, PApplet p, int l) {
		super(p);
		parent = p;		
		annotationType = type;
		groupName = gType;
		parentType = pType;
		annotationOrder = Main1.annotationOrder;
		annotationSubGroups = Main1.annotationSubGroups;
		genes = g;
		level = l;
		myLevels = 1;
		isActiveItem = false;
		isInRing = true;
		isInCenter = false;
		createAnnotations();
	}
	public Annotations(String type, String gType, String pType, Gene [] g, PApplet p, int l, Annotations par) {
		super(p);
		parent = p;		
		parentAnnotations = par;
		annotationType = type;
		groupName = gType;
		parentType = pType;
		annotationOrder = Main1.annotationOrder;
		annotationSubGroups = Main1.annotationSubGroups;
		genes = g;
		level = l;
		myLevels = par.myLevels;
		isActiveItem = false;
		isInRing = true;
		isInCenter = false;
		createAnnotations();
	}
	public Annotations(Annotations a, int newMyLevels) {
		super(Annotations.parent);	
		parentAnnotations = a.parentAnnotations;
		groupName = a.groupName;
		parentType = a.parentType;
		annotationOrder = a.annotationOrder;
		annotationSubGroups = a.annotationSubGroups;
		genes = a.genes;
		level = a.level;
		children = a.children;
		myLevels = newMyLevels;
		annotationType = annotationOrder[level-1];
		if( myLevels > Main1.LEVELS) Main1.LEVELS = myLevels;
		isActiveItem = false;
		isInRing = true;
		isInCenter = false;
		createAnnotations();
	}
	public Annotations(Annotations a, Gene[] newGenes) {
		super(Annotations.parent);	
		parentAnnotations = a.parentAnnotations;
		groupName = a.groupName;
		parentType = a.parentType;
		annotationOrder = a.annotationOrder;
		annotationSubGroups = a.annotationSubGroups;
		genes = newGenes;
		level = a.level;
		children = a.children;
		myLevels = a.myLevels;
		if(level> annotationOrder.length - 1) annotationType = "All";
		else annotationType = annotationOrder[level-1];
		if( myLevels > Main1.LEVELS) Main1.LEVELS = myLevels;
		isActiveItem = false;
		isInRing = true;
		isInCenter = false;
		createAnnotations();
	}
	
		
	public void createAnnotations()
	{
		int groupNum= 0;
		if(annotationType.equals("All"))
		{
			numChildren = 0;
			ArrayList<ArrayList<Gene>> subGroupsCopy = new ArrayList<ArrayList<Gene>>();
			ArrayList<Gene> subGroup = new ArrayList<Gene>();
			subGroupsCopy.add(subGroup);
			for( Gene gene: genes)
			{
				subGroup.add(gene);
				gene.groupHeigherarchy[0] = this;
			}
			subGroups = subGroupsCopy;
			
		}
		else 
		{
			for(int k = 0; k< annotationOrder.length; k++)
			{
				if(annotationType.equals(annotationOrder[k]))
				{
					groupNum = k;
					numChildren = annotationSubGroups[k].length;
					bounds  = new float[numChildren][2];
					ArrayList<ArrayList<Gene>> subGroupsCopy = new ArrayList<ArrayList<Gene>>();
					for(int i = 0; i< numChildren; i++)
					{
						ArrayList<Gene> subGroup = new ArrayList<Gene>();
						subGroupsCopy.add(subGroup);
					}
					if(genes != null)
						for (Gene gene: genes)
						{
							if(level <= 4) gene.groupHeigherarchy[level] = this;
							gene.numAnnotations = level;
							for (int i = 0; i<numChildren; i++)
							{
								if (gene.annotations.get(Main1.annotationColumn[k]).equals(annotationSubGroups[k][i])) 
								{
									subGroupsCopy.get(i).add(gene);					
								}
							}
						}
					subGroups = subGroupsCopy;
				}
			}
		}
		
			
		children = new Annotations[numChildren];
		for (int i = 0; i< numChildren; i++)
		{
			ArrayList<Gene> geneList = (ArrayList<Gene>)subGroups.get(i);
			Gene[] geneList1  = new Gene[geneList.size()];				
			for( int j = 0; j< geneList1.length; j++ )
			{
				geneList1[j] = geneList.get(j);
			}
			if(level >= myLevels)
				children[i] = new Annotations("All", 			   annotationSubGroups[groupNum][i], annotationType, geneList1, parent, myLevels+1,this);
			else
			{
				if (level == 3)
					children[i] = new Annotations(annotationOrder[3], annotationSubGroups[groupNum][i], annotationType, geneList1, parent, 4,this);
				if (level == 2)
					children[i] = new Annotations(annotationOrder[2], annotationSubGroups[groupNum][i], annotationType, geneList1, parent, 3,this);
				if (level == 1)
					children[i] = new Annotations(annotationOrder[1], annotationSubGroups[groupNum][i], annotationType, geneList1, parent, 2,this);
			}
		}
			if(level != myLevels || level == 0)
			{
				groupTotalExpression  = 0;
				int column = Main1.ringProtein.columnInData;
				int dataset = -1;
				for( int i = 0; i< ReadGenes.datasets.length; i++)
				{
					if(Main1.ringProtein.set.equals(ReadGenes.datasets[i]))
						dataset = i;
				}					
				for( int j = 0; j< genes.length; j++ )
				{
					if(Main1.uniformGeneSize) groupTotalExpression = groupTotalExpression + 1f;
					else 
					{
						if(Main1.ringProtein.type.equals("Raw"))
						{
							if(Main1.fractionExpression) groupTotalExpression = groupTotalExpression + genes[j].percentExpressionConditions.get(dataset)[column];
							else groupTotalExpression = groupTotalExpression + Math.abs(genes[j].expressionConditions.get(dataset)[column]);
						}
						else
							groupTotalExpression = (float) (groupTotalExpression + Math.pow(1.0-genes[j].expressionConditions.get(dataset)[column],10))+ .005f;
					}
				}
				for( Gene gene: genes) gene.groupHeigherarchy[0] = this;
			}
			else
			{
				groupTotalExpression = 0;
				for (int i = 0; i< numChildren; i++)
				{
					groupTotalExpression = groupTotalExpression + children[i].groupTotalExpression;
				}
			}
		for (int i = 0; i< numChildren; i++)
		{
			children[i].percentParentExpression = children[i].groupTotalExpression / groupTotalExpression;
		}
		
	}
	
	public void drawGroup(float pieSectionStart, float pieSectionEnd, int level, String split)
	{	
		int end = 0;
		int start = 0;
		float groupTotalExpression1 = 0;		
		
		if(split.equals("Rest") && level == 1)
		{
			end  = children.length -1;
			groupTotalExpression1 = groupTotalExpression - children[end].groupTotalExpression;		
		}
		else if(split.equals("None") && level == 1)
		{
			end  = children.length;
			start = children.length-1;
			groupTotalExpression1 = children[children.length-1].groupTotalExpression;
		}
		else
		{
			end = children.length;
			groupTotalExpression1  = groupTotalExpression;
		}
		for(int i= start; i< end; i++)
		{
			float pt = (float) Math.pow(.5, level-1);
			if(Main1.updateRings)
			{
				Annotations child = children[i];
				float subSectionStart = pieSectionStart;
				float subSectionEnd = pieSectionEnd;
				if( !split.equals("None"))
				{
					for(int k = 0; k< i; k++) subSectionStart = (float)(subSectionStart + (float)((pieSectionEnd - pieSectionStart)*(children[k].groupTotalExpression/groupTotalExpression1)));
					subSectionEnd = subSectionStart + (float)(pieSectionEnd - pieSectionStart)*(child.groupTotalExpression/groupTotalExpression1);
				}													
				bounds[i][0] = subSectionStart;
				bounds[i][1] = subSectionEnd;				
				
				//if(level != myLevels+1)
				{
					children[i].centerX = (float) Math.cos((subSectionEnd - subSectionStart)/2 + subSectionStart)*centerRadius[level-1];
					children[i].centerY = (float) Math.sin((subSectionEnd - subSectionStart)/2 + subSectionStart)*centerRadius[level-1];
				}
					children[i].labelX = (float)  Math.cos((subSectionEnd - subSectionStart)/2 + subSectionStart)*(Main1.innerRadius+pt*(Main1.outerRadius-Main1.innerRadius));
					children[i].labelY = (float) -Math.sin((subSectionEnd - subSectionStart)/2 + subSectionStart)*(Main1.innerRadius+pt*(Main1.outerRadius-Main1.innerRadius));
					children[i].midX = (float)  Math.cos((subSectionEnd - subSectionStart)/2 + subSectionStart)*(Main1.innerRadius);
					children[i].midY = (float) -Math.sin((subSectionEnd - subSectionStart)/2 + subSectionStart)*(Main1.innerRadius);
				
			}		
			
			if (annotationType.equals("Cell Cycle")) parent.fill(cellCycle(i));
			else if (annotationType.equals("Pheremone")) parent.fill(pheremone(i));
			else if (annotationType.equals("Stress")) parent.fill(stress(i));
			else if (annotationType.equals("Origins")) parent.fill(origins(i));
			else parent.fill(generalColor(i));
			parent.stroke(0);
			parent.strokeWeight(3);
			
			parent.arc(0, 0, (Main1.innerRadius+ pt*(Main1.outerRadius-Main1.innerRadius))*2, (Main1.innerRadius+pt*(Main1.outerRadius-Main1.innerRadius))*2, (float) (2*Math.PI - bounds[i][1]), (float) (2*Math.PI - bounds[i][0]));
			parent.strokeWeight(1);
			
			if(children[i].level != children[i].myLevels + 1 )
				children[i].drawGroup(bounds[i][0], bounds[i][1], level+1,"All");
			
			else if(Main1.updateRings)
			{
				ArrayList<Gene> subGroup = (ArrayList<Gene>) subGroups.get(i);
				double placeHolder = bounds[i][0];
				
				int column = Main1.ringProtein.columnInData;
				int dataset = -1;		
				for( int z = 0; z< ReadGenes.datasets.length; z++)
				{
					if(Main1.ringProtein.set.equals(ReadGenes.datasets[z]))
						dataset = z;
				}	
				
				for (int j = 0; j< subGroup.size(); j++)
				{
					Gene gene = subGroup.get(j);
					double sectionStake;
					if(Main1.uniformGeneSize) 
						sectionStake = 1f/children[i].groupTotalExpression;
					else if(Main1.ringProtein.type.equals("Raw"))
					{
						if(Main1.fractionExpression) sectionStake = genes[j].percentExpressionConditions.get(dataset)[column]/children[i].groupTotalExpression;
						else sectionStake = Math.abs(gene.expressionConditions.get(dataset)[column])/children[i].groupTotalExpression;						
					}
					else
						sectionStake = (Math.pow(1.0 - gene.expressionConditions.get(dataset)[column],10)+.005f)/children[i].groupTotalExpression;
					gene.x = Math.cos((bounds[i][1]- bounds[i][0])*(sectionStake/2) + placeHolder);
					gene.y = Math.sin((bounds[i][1]- bounds[i][0])*(sectionStake/2) + placeHolder);
					placeHolder = (bounds[i][1]- bounds[i][0])*(sectionStake) + placeHolder;
				}
			}				
			
		}
		if( isActiveItem ) drawMe(true);
	}
	
	public void drawMe( boolean findMouse)
	{
		if(findMouse)
		{
			x1 = parent.mouseX - parent.width/2 + Main1.xTranslate;
			y1 = parent.mouseY - parent.height/2;
		}
		float lengthFromOrigin = Main1.dist(x1,y1,0,0);
		if (lengthFromOrigin > Main1.outerRadius)
		{    			
			width = parent.width*.05f;
			height = parent.width*.02f;				
			parent.fill(255);
			if (isSelected) parent.fill(parent.color(255,255,0));
			parent.noStroke();
			parent.ellipse(x1,y1,width,height);
			parent.textFont(Main1.font10);
			parent.fill(255,0,0);
			parent.rectMode(Main1.CENTER);
			parent.text(groupName, x1-width/5, y1+6);
			
			if(isInRing)
			{
				annotationCopy = new Annotations(this, genes);
				Gene[] geneCopy = null;					
				java.util.List<Gene> list = Arrays.asList(Main1.firstAnnotation.genes);
				Set<Gene> s = new HashSet<Gene>(list);
				java.util.List<Gene> list2 = Arrays.asList(genes);
				s.removeAll(list2);	
				geneCopy = s.toArray(new Gene[0]);
				Annotations firstAnnotationCopy = Main1.firstAnnotation;
				Main1.firstAnnotation = new Annotations(Main1.firstAnnotation, geneCopy);
				setLevels(Main1.firstAnnotation, firstAnnotationCopy);
				isInRing = false;
				Main1.inactiveItems.add(this);
				Main1.updateRings = true;
				Main1.annotationPopup = null;
				Main1.loop = true;
				parent.loop();
			}
		}
		if(!isInRing  && (lengthFromOrigin < Main1.outerRadius))
		{
			Gene[] geneCopy = null;					
			java.util.List<Gene> list = Arrays.asList(Main1.firstAnnotation.genes);
			Set<Gene> s = new HashSet<Gene>(list);
			java.util.List<Gene> list2 = Arrays.asList(genes);
			s.addAll(list2);	
			geneCopy = s.toArray(new Gene[0]);
			Annotations firstAnnotationCopy = Main1.firstAnnotation;
			Main1.firstAnnotation = new Annotations(Main1.firstAnnotation, geneCopy);
			setLevels(Main1.firstAnnotation, firstAnnotationCopy);
			isInRing = true;
			Main1.updateRings = true;
			Main1.annotationPopup = null;
			Main1.loop = true;
			parent.loop();
		}
	}
	public static void createNewAnnotation( Protein protein, float[] cutoffs, String[] names, PApplet p)
	{
		int dataset = -2;
		BooleanGroup b = null;
		boolean isProtein = false;
		int columnInData = protein.columnInData;
		for( int i = 0; i< ReadGenes.datasets.length; i++)
		{
			if(protein.annotation.equals(ReadGenes.datasets[i]))
				dataset = i;
			else if (protein.set.equals(ReadGenes.datasets[i]))
			{
				dataset = i;
				isProtein = true;
			}
		}
		if(protein.type.equals("Boolean")) 
		{
			dataset = -1;
			b = (BooleanGroup) protein;
		}
		
		for(int i = 0; i< Gene.geneList.length; i++)
		{
			Gene gene = Gene.geneList[i];
			boolean flag = true;
			for(int j = 0; j< cutoffs.length; j++)
				if(Main1.percentValues)
				{
					if(((dataset > -1 && gene.percentExpressionConditions.get(dataset)[columnInData] < cutoffs[j]) || (isProtein && gene.expressionConditions.get(dataset)[columnInData] < cutoffs[j])) && flag || (dataset == -1 && b.percentExpression(i) < cutoffs[j]) && flag)
					{
						gene.annotations.add(gene.annotations.size(), names[j]);
						flag  = false;
					}
				}
				else 
				{
					if(((dataset > -1 && gene.expressionConditions.get(dataset)[columnInData] < cutoffs[j]) || (isProtein && gene.expressionConditions.get(dataset)[columnInData] < cutoffs[j])) && flag)
					{
						gene.annotations.add(gene.annotations.size(), names[j]);
						flag  = false;
					}
				}
			if(flag) gene.annotations.add(gene.annotations.size(), names[names.length-1]);
		}
		
		String[] annotationOrderCopy = Main1.annotationOrder;
		String[][] annotationSubGroupsCopy = Main1.annotationSubGroups;
		int [] annotationColumnCopy = Main1.annotationColumn;
		String[] annotationOrder = new String[annotationOrderCopy.length + 1];
		String[][] annotationSubGroups = new String[annotationSubGroupsCopy.length + 1][];
		int[] annotationColumn = new int[annotationColumnCopy.length + 1];
		annotationOrder[0] = protein.name;
		annotationSubGroups[0] = names;
		annotationColumn[0] = Gene.geneList[0].annotations.size() -1;
		for(int i = 0; i< annotationOrderCopy.length; i++)
		{
			annotationOrder[i+1] = annotationOrderCopy[i];
			annotationSubGroups[i+1] = annotationSubGroupsCopy[i];
			annotationColumn[i+1] = annotationColumnCopy[i];
		}
		Main1.annotationOrder = annotationOrder;
		Main1.annotationSubGroups = annotationSubGroups;
		Main1.annotationColumn = annotationColumn;
		Main1.firstAnnotation = new Annotations(Main1.annotationOrder[0],"All", "All", Main1.firstAnnotation.genes, p, 1);
	}
	public static void setLevels( Annotations a, Annotations copy)
	{
		if( a == null) return;
		else
			for( int i = 0; i< a.children.length; i++)
			{
				if(a.children[i].myLevels != copy.children[i].myLevels)
					a.children[i] = new Annotations(a.children[i], copy.children[i].myLevels);
				setLevels( a.children[i], copy.children[i]);
			}
	}
	
	public void checkMouseOver()
	{
		if((parent.mouseX-parent.width/2 + Main1.xTranslate) > (x1- width/2) && (parent.mouseX-parent.width/2 + Main1.xTranslate) < (x1 + width/2))
			if((parent.mouseY-parent.height/2) > (y1- height/2) && (parent.mouseY-parent.height/2) < (y1 + height/2))
			{
				isSelected = !isSelected;
				if(Main1.activeItem instanceof Annotations) 
				{
					Annotations p = (Annotations) Main1.activeItem;
					if(p != null) p.isActiveItem = false;
				}
				Main1.activeItem = this;
				isActiveItem = true;
				parent.redraw();
			}
	}
	
	public static int cellCycle( int group)
	{
		if(Main1.lighter)
			return Main1.blendColor(parent.color(255),parent.color(cellCycleInvert(group)), Main1.SUBTRACT);
		else return cellCycleInvert( group);
	}
	public static int cellCycleInvert( int group)
	{
		if (group == 0)
			return parent.color(255,255,0);
		else if (group == 1)
			return parent.color(0,255,0);
		else if (group == 2)
			return  parent.color(0,0,255);
		else if (group == 3)
			return parent.color(255,0,0);
		else if (group == 4)
			return parent.color(255,128,0);
		else 
			return 50;
	}
	public static int generalColor( int group)
	{
		if(Main1.lighter)
			return Main1.blendColor(parent.color(255),parent.color(generalColorInvert(group)), Main1.SUBTRACT);
		else return generalColorInvert( group);
	}
	public static int generalColorInvert( int group)
	{
		if (group % 5 == 0)
			return parent.color(255,255,0);
		else if (group % 5 == 1)
			return parent.color(0,255,0);
		else if (group % 5 == 2)
			return  parent.color(0,0,255);
		else if (group % 5 == 3)
			return parent.color(255,0,0);
		else if (group % 5 == 4)
			return parent.color(255,128,0);
		else return 0;
	}
	public static int pheremone( int group)
	{
		if(Main1.lighter)
			return Main1.blendColor(parent.color(255),parent.color(pheremoneInvert(group)), Main1.SUBTRACT);
		else return pheremoneInvert( group);
	}
	public static int pheremoneInvert( int group)
	{
		if (group == 0)
			return parent.color(255,0,255);
		else if (group == 1)
			return parent.color(128,0,128);
		else 
			return 50;
	}
	public static int stress( int group)
	{
		if(Main1.lighter)
			return Main1.blendColor(parent.color(255),parent.color(stressInvert(group)), Main1.SUBTRACT);
		else return stressInvert( group);
	}
	public static int stressInvert( int group)
	{
		if (group == 0)
			return parent.color(0,255,255);
		else if (group == 1)
			return parent.color(0,128,128);
		else 
			return 50;
	}
	public static int origins( int group)
	{
		if(Main1.lighter)
			return Main1.blendColor(parent.color(255),parent.color(originsInvert(group)), Main1.SUBTRACT);
		else return originsInvert( group);
	}
	public static int originsInvert( int group)
	{
		if (group == 0)
			return parent.color(128,250,0);
		else if (group == 1)
			return parent.color(64,125,0);
		else if (group == 2)
			return parent.color(32,64,0);
		else 
			return 50;
	}
	public static void setCenterRadius()
	{
		centerRadius = new float[4];
		centerRadius[0]= parent.width*.1f;
		centerRadius[1]= parent.width*.125f;
		centerRadius[2]= parent.width*.225f;
		centerRadius[3]= parent.width*.275f;
	}
	public String toString()
	{
		return groupName;
	}
	public void unSelect()
	{
		isActiveItem = false;
	}

}
